Skip to content

Decoder-Only 与自回归 ​

标签
AI/llm
字数
2408 字
阅读时间
10 分钟

完整 Transformer 的哲学是「先理解,再生成」:编码器深入理解整个输入句形成全局上下文记忆,解码器基于这份记忆生成翻译。但 OpenAI 开发 GPT 时换了个更简单的假设(Radford et al., Improving language understanding by generative pre-training, OpenAI 2018):

语言的核心任务,不就是预测下一个最有可能出现的词吗?

回答问题、写故事、生成代码,本质上都是在已有文本序列后面一个词一个词地添加最合理的内容。基于这个假设,GPT 做了一个大胆简化:完全抛弃编码器,只保留解码器。这就是 Decoder-Only 架构。

自回归:形式化 ​

Decoder-Only 的工作模式叫自回归(Autoregressive),过程就是「文字接龙」:

自回归生成循环

  [w1 … w_t](当前上下文)
        │
        ▼
  一次完整前向 ──▶ 词表上的概率分布
        │
        ▼
  取一个 token ──▶ 贪心 / 温度 / top-k(采样参数那一篇的主题)
        │
        ▼
  追加到上下文末尾 ──▶ [w1 … w_t, w_{t+1}]
        │
        └──────────────▶ 回到「一次完整前向」

退出条件:遇到停止符,或达到 max_tokens
每一步都要重跑一次完整前向 —— 这是「推理成本由生成长度决定」的来源

形式化上,它用的是概率链式法则:整段序列的联合概率被分解成一连串条件概率的乘积。

P(w1,…,wT)=∏t=1TP(wt∣w1,…,wt−1)

这个分解是整条线的地基,几个后果都从它推出来:

后果说明
一个目标函数统一所有任务只要把任务表述成文本,就都变成「预测下一个词」
生成必须串行要算 wt 得先有 w1..wt−1 —— 这是 KV Cache 存在的根本原因
每一步的输出是整词表上的分布怎么从这个分布里取词,是 采样参数 的事——贪心、温度、top-k 都作用在这一步
误差会累积前面生成错了,后面的条件分布就都建立在错误前提上(见 Agent Loop 的错误累积)

掩码自注意力:为什么不会「偷看」 ​

训练时模型一次性拿到完整文本,它怎么保证学预测第 t+1 个词时不去看后面的答案?答案是掩码自注意力(Masked Self-Attention)。

机制的位置很关键——在注意力分数矩阵算出来之后、Softmax 归一化之前,应用一个「因果掩码」:

attn_scores = QK^T / sqrt(d_k)
attn_scores = masked_fill(attn_scores, mask == 0, -1e9)   ← 因果掩码:屏蔽当前位置之后的所有词元
attn_probs  = softmax(attn_scores)

把所有位于当前位置之后的词元对应的分数替换成极大负数,过 Softmax 后这些位置的概率变为 0。这样模型在计算任意位置的表示时,从数学上被阻止关注它后面的信息。

掩码的形状是一个下三角矩阵——第 i 行只允许前 i 列参与。

一个实现惯例:用 -1e9 这类「足够大的负数」而不是 -inf。数学上 -inf 过 Softmax 得到精确的 0 更干净,但半精度浮点下容易出现 NaN(涉及 -inf - (-inf) 这类运算)。这是数值稳定性对数学纯洁性的一次常见让步。

生成阶段更直接:未来的词还没生成出来,模型只能把已生成的内容当上下文。

掩码自注意力保证训练时的学习方式与生成时的自回归使用方式一致,模型始终只依赖当前位置之前的信息。这一点是 Decoder-Only 能工作的前提。

因果掩码作用在分数矩阵上,形状是一个下三角。

分数矩阵 S = QKᵀ / √d_k(4 个 token,只看结构不看具体数值)

          w1     w2     w3     w4
   w1   [ s11    s12    s13    s14 ]
   w2   [ s21    s22    s23    s24 ]
   w3   [ s31    s32    s33    s34 ]
   w4   [ s41    s42    s43    s44 ]

masked_fill(mask == 0, -1e9) 之后

          w1     w2      w3      w4
   w1   [ s11   -1e9    -1e9    -1e9 ]
   w2   [ s21    s22    -1e9    -1e9 ]
   w3   [ s31    s32     s33    -1e9 ]
   w4   [ s41    s42     s43     s44 ]
          └── 只剩下三角:第 i 行只有前 i 列保留 ──┘

再 softmax(dim=-1):右上角的 −1e9 被压成 0
第 i 个位置在数学上无法看到它后面的任何 token。

训练侧的另一半:shifted labels ​

掩码解决的是「模型不会看到未来」,但还有一个问题:一次前向只有一次,怎么一次性得到 T 个位置的训练信号?

答案是把标签整体左移一位:

输入  x:  [w1, w2, w3, w4]
标签  y:  [w2, w3, w4, w5]      ← 整体左移一位

于是同一次前向的 T 个位置上,各有一个「预测下一个词」的训练信号

位置 1   看到 [w1]              要预测 w2
位置 2   看到 [w1 w2]           要预测 w3
位置 3   看到 [w1 w2 w3]        要预测 w4
位置 4   看到 [w1 w2 w3 w4]     要预测 w5
          └─ 配合因果掩码,每个位置只用到它前面的信息 ─┘
                          │
                          ▼
                一次前向 = T 个训练信号

对照生成侧(同一个分解的两面)
  训练:T 个位置一次算完         ← 参数规模能推到万亿的前提
  生成:T 个 token 要 T 次前向   ← 推理成本由生成长度决定

于是一次前向同时在 T 个位置上产生 T 个「预测下一个词」的训练信号。这带来两个重要收益:

  • 训练是高度并行的(虽然生成是串行的)——这个不对称是 Decoder-Only 能训到万亿参数的关键
  • 配合因果掩码,每个位置都只能用到它前面的信息,与推理时的条件分布严格对应

这种「用真实的前缀作为每一步的输入」的训练方式通常叫 teacher forcing。它有一个已知的副作用:训练时模型看到的前缀永远是正确的,推理时看到的却包含自己生成的错误——这个训练与推理的分布差异,是曝光偏差(exposure bias)问题的来源。

与另外两种架构的对照 ​

理解了 Decoder-Only 的选择,要放到三条路线的对照里才看得清:

Encoder-OnlyEncoder-DecoderDecoder-Only
代表BERT原始 Transformer、T5GPT 系列、Llama、Qwen
注意力双向(能看到两侧)编码器双向 + 解码器因果因果(只看左侧)
预训练目标掩码语言建模(完形填空)去噪 / 序列到序列下一个词预测
天然擅长理解类:分类、抽取、相似度转换类:翻译、摘要生成类:对话、写作、代码
生成能力没有(非自回归,不是生成模型)有有
统一任务的方式加一个任务头输入-输出两个序列把任务写成 prompt

最后一行是 Decoder-Only 真正的胜出原因。前三代架构要给每类任务配不同的头或不同的训练流程;Decoder-Only 只需要把任务表述成文本续写——分类就是把标签写成下一个词,抽取就是把答案写成后续文本。架构不区分任务,任务在数据里。

三条优势 ​

优势说明
训练目标统一唯一任务是「预测下一个词」,非常适合在海量无标注文本上做预训练
训练并行、生成串行靠 shifted labels,一次前向产生 T 个信号——训练侧可以吃满算力,这让参数规模能推到数千亿到万亿(GPT-4、Llama)
天然适合生成任务自回归模式与对话、写作、代码生成等所有生成式任务契合
不预设任务结构任务通过 prompt 表达而不是通过架构表达——这才有了后续「同一个模型什么都干」的形态

「训练并行、生成串行」这个不对称值得单独记住:它同时解释了两件事——为什么这类模型能训得那么大,以及为什么推理成本会由生成长度决定(每个 token 都要一次完整前向)。

相关 ​

参考 ​

  • 《Hello-Agents》第三章 §3.1.3
  • Radford, A., et al. Improving language understanding by generative pre-training. OpenAI, 2018.
  • 本专栏 02-Transformer 架构 的 Encoder-Decoder 一节

贡献者 ​

文件历史 ​